home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
c
/
cpptask1.zip
/
TASK.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-07
|
4KB
|
181 lines
/**********************************************************************
*
* NAME: task.cpp
*
* DESCRIPTION: modified version of Bruce Eckel's C++ task manager
* from Computer Language Feb. 1991
*
* M O D I F I C A T I O N H I S T O R Y
*
* when who what
* -------------------------------------------------------------------
* 02/04/91 J. Alan Eldridge created
*
* 02/05/91 JAE modified so it would run: made each
* task have its own stack to eliminate
* the stack copying (which is not only
* ugly and limitng, but dangerous as well)
*
* added semaphores for task waiting
*
*********************************************************************/
#include "aedef.h"
#include "task.h"
void
tskFatal(char *fmt, ...)
{
va_list ap;
fprintf(stderr, "TASKER FATAL ERROR: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
exit(EXIT_FAILURE);
}
void
TskList::append(TskObj *pObj)
{
if (!cObj++)
pHead = pTail = pObj;
else {
pTail->linkTo(pObj);
pTail = pObj;
}
}
void
Task::init()
{
static Task *saveThis; // must be static ...
saveThis = this; // ... need to do this 'cause we're changing stacks
// and "this" is an invisible arg on the stack
stack = (uchar far *) new uchar [ stkLen ]; // allocate new stack
// off to Mars ...
_SP = FP_OFF(stack) + stkLen;
_SS = FP_SEG(stack);
// call using saved value ...
saveThis->tskMain(); // ... and never come back
// if we get here, something's _really_ wrong ...
tskFatal("returned from tskMain() in task %s\n", name());
}
void
Task::suspend()
{
if (!setjmp(tskEnv))
owner.giveUpTask();
}
void
Task::resume()
{
longjmp(tskEnv, 1);
}
void
Scheduler::runATask()
{
int cTask = tasks.count();
for (int n = 0; n < cTask; n++) {
if (pTask)
pTask = (Task *)(pTask->next());
if (!pTask)
pTask = (Task *)(tasks.first());
if (!pTask->isReady())
continue;
if (!pTask->isInited())
pTask->init(); // never return except by longjmp()
// to setjmp() at beginning of function
else
pTask->resume(); // just go back after last suspend()
}
}
void
Scheduler::run()
{
if (setjmp(schEnv) == -1) // look for endProcess() call
return;
runATask(); // try to run next available task
tskFatal("deadlock!! all tasks are blocked");
}
Task::Task(uchar *name, Scheduler &s, int len):
tName(name), owner(s), stkLen(len), stack(0), ready(1)
{
owner.addTask(this);
}
Task::~Task() // note this is a virtual function
{
delete stack;
}
Sema *
Scheduler::findSema(uchar *semaName)
{
for (Sema *pSema = (Sema *)(semas.first()); pSema;
pSema = (Sema *)(pSema->next()))
if (!strcmp(semaName, pSema->name()))
break;
if (!pSema)
tskFatal("semaphore %s not found", semaName);
return pSema;
}
void
Scheduler::signalSema(uchar *semaName, Task *t, int units)
{
findSema(semaName)->signal(t, units);
}
void
Scheduler::waitSema(uchar *semaName, Task *t)
{
findSema(semaName)->wait(t);
}
void
Sema::signal(Task *t, int units)
{
value += units;
if (value > 0 && tskWaiting) {
tskWaiting->makeReady();
tskWaiting = 0;
}
t->suspend();
}
void
Sema::wait(Task *t)
{
if (tskWaiting)
tskFatal("task %s tried to wait on semaphore %s, " // no comma!
"already used by task %s",
t->name(), name(), tskWaiting->name());
tskWaiting = t;
if (value > 0) // handle initial case where sema is disabled
value--; // but nobody's waiting on it yet
if (value < 1) {
t->makeWait();
t->suspend();
}
}